using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.IO;
using System.Xml;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Graphics.PackedVector;



namespace TerrainToXML
{
	public class Game1 : Microsoft.Xna.Framework.Game
	{
		GraphicsDeviceManager graphics;
		SpriteBatch spriteBatch;

		public Game1()
		{
			graphics = new GraphicsDeviceManager(this);
			Content.RootDirectory = "Content";
		}



		protected override void Initialize()
		{
			// Add your initialization logic here

			base.Initialize();
		}



		void AddVertex(XmlDocument xmlDocument, /*String posX, String posZ,*/ String h, String normX, String normY, String normZ)
		{
			XmlElement vertexNode = xmlDocument.CreateElement("Vertex");
			xmlDocument.DocumentElement.AppendChild(vertexNode);

			/*
				XmlElement position = xmlDocument.CreateElement("NormalizedPosition");
				vertexNode.AppendChild(position);

					XmlElement x = xmlDocument.CreateElement("X");
					position.AppendChild(x);

						XmlText xText = xmlDocument.CreateTextNode(posX);
						x.AppendChild(xText);

					XmlElement z = xmlDocument.CreateElement("Z");
					position.AppendChild(z);

						XmlText zText = xmlDocument.CreateTextNode(posZ);
						z.AppendChild(zText);
			*/
				XmlElement height = xmlDocument.CreateElement("Height");
				vertexNode.AppendChild(height);

					XmlText heightText = xmlDocument.CreateTextNode(h);
					height.AppendChild(heightText);

				XmlElement normal = xmlDocument.CreateElement("Normal");
				vertexNode.AppendChild(normal);

					XmlElement nX = xmlDocument.CreateElement("X");
					normal.AppendChild(nX);

						XmlText nXText = xmlDocument.CreateTextNode(normX);
						nX.AppendChild(nXText);

					XmlElement nY = xmlDocument.CreateElement("Y");
					normal.AppendChild(nY);

						XmlText nYText = xmlDocument.CreateTextNode(normY);
						nY.AppendChild(nYText);

					XmlElement nZ = xmlDocument.CreateElement("Z");
					normal.AppendChild(nZ);

						XmlText nZText = xmlDocument.CreateTextNode(normZ);
						nZ.AppendChild(nZText);
		}


		protected override void LoadContent()
		{
			// Create a new SpriteBatch, which can be used to draw textures.
			spriteBatch = new SpriteBatch(GraphicsDevice);

			//################################################################################################
			//############################################ HERE ##############################################
			//################################################################################################

			// Shader parameters... They must match!!!
			const float HEIGHT_SCALE = 48.0f;
			const float ATLAS_DIM = 512.0f;
			const float ATLAS_NUM_COLS = 6.0f;
			const float ATLAS_TILE_DIM = 83.0f;
			const float ATLAS_PADDING = 2.0f;
			//-------------------------------------------------------------------


			const uint TERRAIN_ACTIVE_PATCH = 36;
			const uint TERRAIN_WIDTH = (uint)ATLAS_TILE_DIM;
			const uint TERRAIN_DEPTH = TERRAIN_WIDTH * TERRAIN_ACTIVE_PATCH;


			Texture2D heightMapAtlas = Content.Load<Texture2D>("Textures\\HeightMapAtlas");
			Debug.Assert(heightMapAtlas.Width == ATLAS_DIM && heightMapAtlas.Height == ATLAS_DIM);


			// Init XML document
			XmlDocument xmlDocument = new XmlDocument();
			XmlDeclaration xmlDeclaration = xmlDocument.CreateXmlDeclaration("1.0", "utf-8", null);
			// Create the root element
			xmlDocument.InsertBefore(xmlDeclaration, xmlDocument.DocumentElement);
			XmlElement rootNode = xmlDocument.CreateElement("Terrain");
			xmlDocument.AppendChild(rootNode);

			rootNode.SetAttribute("Width", TERRAIN_WIDTH.ToString());
			rootNode.SetAttribute("Depth", TERRAIN_DEPTH.ToString());
			//-------------------------------------------------------------------


			HalfSingle[] terrainPatchData = new HalfSingle[(int)ATLAS_TILE_DIM * (int)ATLAS_TILE_DIM];

			for(int i = (int)TERRAIN_ACTIVE_PATCH-1; i >= 30; i--)
			{
				int atlasRow = (int)Math.Floor(i/ATLAS_NUM_COLS);
				int atlasCol = i - atlasRow * (int)ATLAS_NUM_COLS;

				int startRow = atlasRow * (int)(ATLAS_TILE_DIM + ATLAS_PADDING);
				int startCol = atlasCol * (int)(ATLAS_TILE_DIM + ATLAS_PADDING);

				Rectangle patchRect = new Rectangle(startCol, startRow, (int)ATLAS_TILE_DIM, (int)ATLAS_TILE_DIM);
				heightMapAtlas.GetData<HalfSingle>(0, patchRect, terrainPatchData, 0, terrainPatchData.Count());

				//Texture2D patch = new Texture2D(GraphicsDevice, (int)ATLAS_TILE_DIM, (int)ATLAS_TILE_DIM, false, SurfaceFormat.HalfSingle);
				//patch.SetData<HalfSingle>(terrainPatchData);
				//FileStream file = new FileStream("D:\\SampleImage.png", FileMode.Create);
				//patch.SaveAsPng(file, (int)ATLAS_TILE_DIM, (int)ATLAS_TILE_DIM);
				//file.Close();

				foreach(HalfSingle h in terrainPatchData)
					AddVertex(xmlDocument, (h.ToSingle() * HEIGHT_SCALE).ToString(), "nX", "nY", "nZ");
			}

			xmlDocument.Save("D:\\Sample.xml");

			//################################################################################################
			//################################################################################################
		}



		protected override void UnloadContent()
		{
			// Unload any non ContentManager content here
		}



		protected override void Update(GameTime gameTime)
		{
			// Allows the game to exit
			if(GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
				this.Exit();

			// Add your update logic here

			base.Update(gameTime);
		}



		protected override void Draw(GameTime gameTime)
		{
			GraphicsDevice.Clear(Color.CornflowerBlue);

			// Add your drawing code here

			base.Draw(gameTime);
		}
	}
}
